package uem

import (
	"bytes"
	"github.com/gin-contrib/sessions"
	"github.com/gin-contrib/sessions/cookie"
	"github.com/gin-gonic/gin"
	"io/ioutil"
	"net/http"
)

type Handle func(schema string, method string, v interface{})

type ControllerInterface interface {
	GetControllerName() string
	SetHttpServer(srv *http.Server)
	GetControllerHandle(router string, handle Handle)
}

var (
	MethodHttpGet    = "GET"
	MethodHttpPost   = "POST"
	MethodHttpDelete = "DELETE"
	MethodHttpPut    = "PUT"
)

type ControllerTables struct {
	List
}

func NewControllerTables() (c *ControllerTables) {

	c = &ControllerTables{}
	return
}
func (c *ControllerTables) AllItem(f func(value ControllerInterface)) {

	c.List.AllList(func(value interface{}) {
		item, ok := value.(ControllerInterface)
		if ok {
			f(item)
		}
	})
}
func (c *ControllerTables) AddController(v interface{}) {

	c.AddNode(v)
}
func (c *ControllerTables) DelController(v interface{}) {

	c.DelNode(v)
}

type Controller struct {
	web *http.Server
}

func (c *Controller) GetSessionKV(context *gin.Context, key interface{}) interface{} {
	session := sessions.Default(context)
	return session.Get(key)
}
func (c *Controller) SetSessionKV(context *gin.Context, key interface{}, val interface{}) {
	session := sessions.Default(context)
	session.Set(key, val)
}
func (c *Controller) DelSessionKV(context *gin.Context, key interface{}) {
	session := sessions.Default(context)
	session.Delete(key)
}
func (c *Controller) SaveSession(context *gin.Context) {
	session := sessions.Default(context)
	session.Save()
}
func (c *Controller) SetHttpServer(web *http.Server) {
	c.web = web
}
func (c *Controller) ServiceFinish(context *gin.Context, status int, res interface{}) {

	context.JSON(status, res)
}

func (c *Controller) ServiceFinishAsciiJSON(context *gin.Context, status int, res interface{}) {

	context.AsciiJSON(status, res)
}

func (c *Controller) ServiceFinishString(context *gin.Context, status int, data string) {
	context.String(status, data)
}

func (c *Controller) SaveBody(context *gin.Context) error {

	data, err := context.GetRawData()
	if err != nil {
		return err
	}

	//warning...
	context.Request.Body = ioutil.NopCloser(bytes.NewBuffer(data))
	return nil
}

// read only one
func (c *Controller) GetBody(context *gin.Context) ([]byte, error) {

	body, err := ioutil.ReadAll(context.Request.Body)
	if err != nil {
		return nil, err
	}

	return body, nil
}

func Cross() gin.HandlerFunc {
	return func(c *gin.Context) {

		method := c.Request.Method
		origin := c.GetHeader("Origin")

		if origin != "" {
			c.Header("Access-Control-Allow-Origin", "*")
			c.Header("Access-Control-Allow-Methods", "POST, GET, OPTIONS, PUT, DELETE, UPDATE")
			c.Header("Access-Control-Allow-Headers", "Origin, X-Requested-With, Content-Type, Accept, Authorization")
			c.Header("Access-Control-Expose-Headers", "Content-Length, Access-Control-Allow-Origin, Access-Control-Allow-Headers, Cache-Control, Content-Language, Content-Type")
			c.Header("Access-Control-Allow-Credentials", "true")
		}
		if method == "OPTIONS" {
			c.AbortWithStatus(http.StatusNoContent)
		}

		c.Next()
	}
}

func Engine(debug bool) http.Handler {

	return NewEngine(debug)
}

func TestLogin(c *gin.Context) {

}
func NewEngine(debug bool) *gin.Engine {

	gin.DisableConsoleColor()
	r := gin.New()

	r.MaxMultipartMemory = 8 << 20

	if debug != true {
		gin.SetMode(gin.ReleaseMode)
	}

	// gin.hook
	//Cross() -> gin.Logger() -> gin.Recovery() -> AuthSession()

	r.Use(Cross())
	r.Use(gin.Logger())
	r.Use(gin.Recovery())

	//http://www.iamlintao.com/7275.html
	//gob.Register(Auth{})
	store := cookie.NewStore([]byte("secret"))

	store.Options(sessions.Options{
		//Path:   "/",
		//Domain: "your-domain.com",  mn
		MaxAge: 30, // cookie 5 min
		//Secure:   true, //
		HttpOnly: true, // JavaScript setting Cookie(no)
		//SameSite: http.SameSiteLaxMode, // SameSite cookie
	})

	r.Use(sessions.Sessions("session", store))
	return r
}

func RegRouterHandlerController(http *http.Server, method string, relativePath string, v interface{}) {

	http.Handler.(*gin.Engine).Handle(method, relativePath, v.(func(*gin.Context)))

}
